package run.halo.app.repository;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.springframework.data.jpa.repository.Query;
import org.springframework.lang.NonNull;
import run.halo.app.model.entity.SiteCategory;
import run.halo.app.model.enums.SiteStatus;
import run.halo.app.model.projection.CategoryIdSiteStatusProjection;
import run.halo.app.repository.base.BaseRepository;


/**
 * Site category repository.
 *
 * @author meazty
 * @since 2022/7/30 14:39
 **/
public interface SiteCategoryRepository extends BaseRepository<SiteCategory, Integer> {

    /**
     * Finds all category ids by site id
     *
     * @param siteId site id must not be null
     * @return a list of category id
     */
    @NonNull
    @Query("select siteCategory.categoryId from SiteCategory siteCategory where siteCategory"
        + ".siteId = ?1")
    Set<Integer> findAllCategoryIdsBySiteId(@NonNull Integer siteId);

    /**
     * Finds all site ids by category id.
     *
     * @param categoryId category id must not be null
     * @return a set of site id
     */
    @NonNull
    @Query("select siteCategory.siteId from SiteCategory siteCategory where siteCategory"
        + ".categoryId = ?1")
    Set<Integer> findAllSiteIdsByCategoryId(@NonNull Integer categoryId);

    /**
     * Finds all site ids by category id and site status.
     *
     * @param categoryId category id must not be null
     * @param status site status must not be null
     * @return a set of site id
     */
    @NonNull
    @Query("select siteCategory.siteId from SiteCategory siteCategory, Site site where "
        + "siteCategory.categoryId = ?1 and site.id = siteCategory.siteId and site.status = ?2")
    Set<Integer> findAllSiteIdsByCategoryId(@NonNull Integer categoryId,
        @NonNull SiteStatus status);

    /**
     * Finds all site ids by category id and site status.
     *
     * @param categoryId category id must not be null
     * @param status site status must not be empty
     * @return a set of site id
     */
    @NonNull
    @Query("select siteCategory.siteId from SiteCategory siteCategory, Site site where"
        + " siteCategory.categoryId = ?1 and site.id = siteCategory.siteId and site.status in (?2)")
    Set<Integer> findAllSiteIdsByCategoryId(
        @NonNull Integer categoryId, @NonNull Set<SiteStatus> status);

    /**
     * Finds all site categories by site id in.
     *
     * @param siteIds site id collection must not be null
     * @return a list of site category
     */
    @NonNull
    List<SiteCategory> findAllBySiteIdIn(@NonNull Collection<Integer> siteIds);

    /**
     * Finds all site categories by site id.
     *
     * @param siteId site id must not be null
     * @return a list of site category
     */
    @NonNull
    List<SiteCategory> findAllBySiteId(@NonNull Integer siteId);

    /**
     * Finds all site categories by category id.
     *
     * @param categoryId category id must not be null
     * @return a list of site category
     */
    @NonNull
    List<SiteCategory> findAllByCategoryId(@NonNull Integer categoryId);

    /**
     * Deletes site categories by site id.
     *
     * @param siteId site id must not be null
     * @return a list of site category deleted
     */
    @NonNull
    List<SiteCategory> deleteBySiteId(@NonNull Integer siteId);

    /**
     * Deletes site categories by category id.
     *
     * @param categoryId category id must not be null
     * @return a list of site category deleted
     */
    @NonNull
    List<SiteCategory> deleteByCategoryId(@NonNull Integer categoryId);

    /**
     * Finds all site categories by category id list.
     *
     * @param categoryIdList category id list must not be empty
     * @return a list of site category
     */
    @Query("select pc from SiteCategory pc where pc.categoryId in (?1)")
    @NonNull
    List<SiteCategory> findAllByCategoryIdList(List<Integer> categoryIdList);

    /**
     * Finds all category ids with site id and status.
     *
     * @return a list of category id and site status
     */
    @NonNull
    @Query("select new run.halo.app.model.projection.CategoryIdSiteStatusProjection(pc.categoryId,"
        + " pc.siteId, p.status) from SiteCategory pc inner join Site p on p.id=pc.siteId")
    List<CategoryIdSiteStatusProjection> findAllWithSiteStatus();
}
